﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PentaBiz.Collections;

namespace PentaBiz.Testing.Collections
{
    
    [TestClass]
    public class UnitTestObjectPool
    {
        [TestMethod]
        [TestCategory("ObjectPool<object>")]
        public void TestObjectPool()
        {
            var op = new ObjectPool<object>(() => new object(), 10);
        }

        [TestMethod]
        [TestCategory("ObjectPool<object>")]
        public void TestObjectPoolGetAll()
        {
            int cnt = 10;
            var op = new ObjectPool<object>(() => new object(), cnt);
            List<object> l = new List<object>(10);
            while (op.PoolSize > 0)
            {
                l.Add(op.GetObject().Instance);
            }

            Assert.AreEqual(cnt, l.Count, "There should be {0} initial objects returned by getobject");
            Assert.AreEqual(0, op.PoolSize, "There should by 0 elemenets in the pool after getall");
        }

        [TestMethod]
        [TestCategory("ObjectPool<object>")]
        public void TestObjectPoolGetAllThenReturn()
        {
            int cnt = 10;
            var op = new ObjectPool<object>(() => new object(), cnt);
            List<object> l = new List<object>(20);
            while (op.PoolSize > 0)
            {
                l.Add(op.GetObject().Instance);
            }

            l.ForEach(op.PutObject);
            //l.Clear();


            Assert.AreEqual(cnt, op.PoolSize, "There should by {0} elemenets in the pool after getall", cnt);
        }

        [TestMethod]
        [TestCategory("ObjectPool<object>Performance")]
        public void TestObjectPoolUsingPerformance()
        {
            var op = new ObjectPool<object>(() => { Thread.Sleep(TimeSpan.FromMilliseconds(2)); return new object(); });
            op.MaximumPoolSize = 10000;


            for (int i = 0; i < 20000; i++)
            {
                using (var o = op.GetObject())
                {

                }
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Assert.AreEqual(1, op.PoolSize, "There should by {0} elemenets in the pool after getall", 1);

        }

        [TestMethod]
        [TestCategory("ObjectPool<object>Performance")]
        public void TestNonObjectPoolUsingPerformance()
        {


            for (int i = 0; i < 20000; i++)
            {
                var o = new object();
                Thread.Sleep(TimeSpan.FromMilliseconds(2));
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();


        }

        [TestMethod, TestCategory("ObjectPool<SlowObject>Performance")]
        public void TestPerformanceComparison()
        {

            SlowObject o;

            var stopWatchNonPooled = new Stopwatch();
            stopWatchNonPooled.Start();
            for (int i = 0; i < 100000; i++)
            {

                o = new SlowObject();
            }
            stopWatchNonPooled.Stop();

            Console.WriteLine("NonPooled {0}", stopWatchNonPooled.Elapsed);

            var op = new ObjectPool<SlowObject>(() => new SlowObject());
            var stopWatchPooled = new Stopwatch();
            stopWatchPooled.Start();
            for (int i = 0; i < 100000; i++)
            {
                o = op.GetObject();
            }
            stopWatchPooled.Stop();

            Console.WriteLine("Pooled {0}", stopWatchPooled.Elapsed);

            Assert.IsTrue(stopWatchPooled.Elapsed < stopWatchNonPooled.Elapsed, "Pool performance must be better than nonPooled performance");

        }
    }

    class SlowObject
    {
        public SlowObject()
        {
            Thread.Sleep(TimeSpan.FromMilliseconds(1));
        }
    }
}
